#include "StdAfx.h"
#include "AnimatedImage.h"
#include "GraphicsController.h"
#include <string>
#include <stdexcept>


///////////////////////////////////////////////////////////////////////////////

DWORD CAnimatedImageVertex::FVF = D3DFVF_XYZ | D3DFVF_TEX1;

///////////////////////////////////////////////////////////////////////////////

AnimatedImage::AnimatedImage(CGraphicsController& graphicsController,
                             const std::wstring& fileName,
                             UINT numFrames,
                             UINT frameWidth,
                             UINT frameHeight,
                             bool transparent)
      : m_graphicsController(graphicsController),
      m_imageTexture(NULL),
      m_vertices(NULL),
      m_frameWidth(frameWidth),
      m_frameHeight(frameHeight),
      m_transparent(transparent),
      m_animationFrame(0)
{
   // load the texture
   D3DXIMAGE_INFO imageInfo;
   m_imageTexture = m_graphicsController.loadTextureFromFile(fileName, &imageInfo, 0xFF000000);

   m_texFrameWidth = (float)frameWidth / (float)(imageInfo.Width - 1);
   m_texFrameHeight = (float)frameHeight / (float)(imageInfo.Height - 1);

   // create the vertices
   m_vertices = m_graphicsController.createVertexBuffer(4 * sizeof(CAnimatedImageVertex),
                                                        D3DUSAGE_WRITEONLY,
                                                        CAnimatedImageVertex::FVF,
                                                        D3DPOOL_MANAGED);

   CAnimatedImageVertex* pVertex = NULL;
   HRESULT res = m_vertices->Lock(0, 0, (void**)&pVertex, D3DLOCK_DISCARD);
   if (FAILED(res))
   {
      throw std::logic_error(
         std::string("Cannot lock a vertex buffer"));
   }

   *pVertex++ = CAnimatedImageVertex(0,            0,             0,               0);
   *pVertex++ = CAnimatedImageVertex(m_frameWidth, 0,             m_texFrameWidth, 0);
   *pVertex++ = CAnimatedImageVertex(0,            m_frameHeight, 0,               m_texFrameHeight);
   *pVertex++ = CAnimatedImageVertex(m_frameWidth, m_frameHeight, m_texFrameWidth, m_texFrameHeight);

   m_vertices->Unlock();

   // reset the world matrix
   D3DXMatrixIdentity(&m_mtxWorld);

   // calculate animation matrices
   for (UINT i = 0; i < numFrames; ++i)
   {
      D3DXMATRIX mtxTmp;
      D3DXMatrixIdentity(&mtxTmp);

      mtxTmp._31 = m_texFrameWidth * i;

      m_mtxTex.push_back(mtxTmp);
   }
}

///////////////////////////////////////////////////////////////////////////////

AnimatedImage::~AnimatedImage(void)
{
   m_imageTexture->Release();
   m_imageTexture = NULL;

   m_vertices->Release();
   m_vertices = NULL;
}

///////////////////////////////////////////////////////////////////////////////

void AnimatedImage::setPosition(float x, float y)
{
   m_mtxWorld._41 = x * m_graphicsController.getBackBufferWidth();
   m_mtxWorld._42 = y * m_graphicsController.getBackBufferHeight();
}

///////////////////////////////////////////////////////////////////////////////

float AnimatedImage::getWidth() const
{
   UINT screenWidth = m_graphicsController.getBackBufferWidth();
   return (float)m_frameWidth / screenWidth;
}

///////////////////////////////////////////////////////////////////////////////

float AnimatedImage::getHeight() const
{
   UINT screenHeight = m_graphicsController.getBackBufferHeight();
   return (float)m_frameHeight / screenHeight;
}

///////////////////////////////////////////////////////////////////////////////

void AnimatedImage::advanceFrame()
{
   m_animationFrame++;

   if (m_animationFrame >= m_mtxTex.size())
   {
      m_animationFrame = 0;
   }
}

///////////////////////////////////////////////////////////////////////////////

void AnimatedImage::render(CViewFrustrum& frustrum, IDirect3DDevice9& d3Device)
{
   d3Device.SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
   d3Device.SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
   d3Device.SetRenderState(D3DRS_LIGHTING, FALSE);
   d3Device.SetRenderState(D3DRS_SPECULARENABLE, FALSE);

   if (m_transparent)
   {
      d3Device.SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
   }

   d3Device.SetTexture(0, m_imageTexture);
   d3Device.SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2);
   d3Device.SetTransform(D3DTS_TEXTURE0, &(m_mtxTex[m_animationFrame]));
   /*d3Device.SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCCOLOR);
   d3Device.SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);*/

   d3Device.SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCCOLOR);
   d3Device.SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCCOLOR);

   d3Device.SetTransform(D3DTS_WORLD, &m_mtxWorld);
   d3Device.SetFVF(CAnimatedImageVertex::FVF);
   d3Device.SetStreamSource(0, m_vertices, 0, sizeof(CAnimatedImageVertex));
   d3Device.DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);

   d3Device.SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE);

   d3Device.SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
   d3Device.SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
   d3Device.SetRenderState(D3DRS_LIGHTING, TRUE);
   d3Device.SetRenderState(D3DRS_SPECULARENABLE, TRUE);
   d3Device.SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
}

///////////////////////////////////////////////////////////////////////////////
